package com.arpa.wms.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.arpa.ntocc.common.common.cache.PartyCache;
import com.arpa.ntocc.common.common.util.CommonUtil;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.wms.domain.consts.NumConst;
import com.arpa.wms.domain.dto.GoodsUnitConversionDTO;
import com.arpa.wms.domain.entity.GoodsUnitConversion;
import com.arpa.wms.domain.vo.GoodsUnitConversionVO;
import com.arpa.wms.mapper.GoodsUnitConversionMapper;
import com.arpa.wms.service.IGoodsUnitConversionService;
import com.arpa.wms.service.IGoodsUnitService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.qimen.api.request.ItemsSynchronizeRequest;
import com.qimen.api.request.SingleitemSynchronizeRequest;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品单位换算 服务实现类
 * </p>
 *
 * @author LEO
 * @since 2020-08-03
 */
@Service
@Log4j2
public class GoodsUnitConversionServiceImpl extends ServiceImpl<GoodsUnitConversionMapper, GoodsUnitConversion> implements IGoodsUnitConversionService {

    @Autowired
    private PartyCache partyCache;

    /**
     * 保存
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor={Exception.class})
    public boolean save(GoodsUnitConversion entity) {
        if(StringUtils.isBlank(entity.getCode())){
            entity.setCode(IdUtil.simpleUUID());
        }
        entity.setGroupCode(UserUtil.getBranchCode());
        if(StringUtils.isBlank(entity.getCreatedBy())){
            entity.setCreatedBy(UserUtil.getCode());
        }
        return super.save(entity);
    }

    /**
     * 根据code更新实体
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor={Exception.class})
    public int updateByCode(GoodsUnitConversion entity) {
        if(StringUtils.isBlank(entity.getModifiedBy())){
            entity.setModifiedBy(UserUtil.getCode());
        }
        return baseMapper.update(entity,new QueryWrapper<GoodsUnitConversion>().lambda().eq(GoodsUnitConversion::getCode,entity.getCode()).eq(GoodsUnitConversion::getGroupCode,UserUtil.getBranchCode()));
    }

    /**
     * 查询列表
     * @param goodsUnitConversionDTO
     * @return
     */
    @Override
    public List<GoodsUnitConversionVO> queryList(GoodsUnitConversionDTO goodsUnitConversionDTO){
        //排序字段名需要驼峰转数据库下划线类型字段名
        if(StringUtils.isNotEmpty(goodsUnitConversionDTO.getSortField())){
            goodsUnitConversionDTO.setSortField(CommonUtil.camel2Underline(goodsUnitConversionDTO.getSortField()));
        }
        List<GoodsUnitConversionVO> goodsUnitConversionVOList = baseMapper.queryList(goodsUnitConversionDTO);
        return goodsUnitConversionVOList;
    }

    @Override
    public List<GoodsUnitConversionVO> queryListByGoodsCodes(List<String> goods) {
        BigDecimal oneHundred = new BigDecimal("100");
        BigDecimal oneThousand = new BigDecimal("1000");
        //将长、宽、高装换为米，体积装换为立方米；初始长、宽、高默认为cm,体积默认为升，重量默认为KG,和奇门保持一致；
        return baseMapper.queryListByGoodsCodes(goods).stream().peek(e -> {
            if (null != e.getLength() && e.getLength().compareTo(BigDecimal.ZERO) > 0) {
                e.setLength(e.getLength().divide(oneHundred).setScale(3, BigDecimal.ROUND_HALF_UP));
            }
            if (null != e.getWidth() && e.getWidth().compareTo(BigDecimal.ZERO) > 0) {
                e.setWidth(e.getWidth().divide(oneHundred).setScale(3, BigDecimal.ROUND_HALF_UP));
            }
            if (null != e.getHeight() && e.getHeight().compareTo(BigDecimal.ZERO) > 0) {
                e.setHeight(e.getHeight().divide(oneHundred).setScale(3, BigDecimal.ROUND_HALF_UP));
            }
            if (null != e.getVolume() && e.getVolume().compareTo(BigDecimal.ZERO) > 0) {
                e.setVolume(e.getVolume().divide(oneThousand).setScale(6, BigDecimal.ROUND_HALF_UP));
            }
        }).collect(Collectors.toList());
    }

    /**
     * 查询合计,包含总数
     * @param goodsUnitConversionDTO
     * @return
     */
    @Override
    public GoodsUnitConversionVO queryListSum(GoodsUnitConversionDTO goodsUnitConversionDTO){
        GoodsUnitConversionVO goodsUnitConversionVO = baseMapper.queryListSum(goodsUnitConversionDTO);
        return goodsUnitConversionVO;
    }

    @Override
    public List<GoodsUnitConversion> selectList(LambdaQueryWrapper<GoodsUnitConversion> eq) {
        return this.baseMapper.selectList(eq);
    }

    /**
     * 批量同步商品时，根据操作类型判断是插入还是更新
     *
     * @param request
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void batchGoodsUnitConversionSave(ItemsSynchronizeRequest request, Map<String,String> unitMap){
        String shipmentPartyCode = request.getOwnerCode();
        List<ItemsSynchronizeRequest.Item> items = request.getItems();
        List<GoodsUnitConversion> goodsUnitConversionList = Lists.newArrayList();
        for (ItemsSynchronizeRequest.Item item : items) {
            //删除原有商品基本单位转换关系
            String goodsCode = item.getItemCode();
            this.remove(new QueryWrapper<GoodsUnitConversion>().lambda().eq(GoodsUnitConversion::getGoodsCode, goodsCode)
                    .eq(GoodsUnitConversion::getFlag, NumConst.NUM_ONE).eq(GoodsUnitConversion::getDeleted,"0"));
            String unitName = item.getStockUnit();
            //根据货主code和单位名称查询单位信息
            GoodsUnitConversion goodsUnitConversion = new GoodsUnitConversion();
            goodsUnitConversion.setGoodsCode(goodsCode);
            goodsUnitConversion.setUnitCode(unitMap.get(shipmentPartyCode+"_"+unitName));
            goodsUnitConversion.setUnitName(item.getStockUnit());
            goodsUnitConversion.setLength(new BigDecimal(item.getLength()));
            goodsUnitConversion.setWeight(new BigDecimal(item.getWidth()));
            goodsUnitConversion.setHeight(new BigDecimal(item.getHeight()));
            goodsUnitConversion.setWeight(new BigDecimal(item.getVolume()));
            goodsUnitConversion.setVolume(new BigDecimal(item.getGrossWeight()));
            goodsUnitConversion.setGmtCreated(LocalDateTime.now());
            goodsUnitConversion.setCreatedBy(UserUtil.getCode());
            goodsUnitConversion.setCreatedName(partyCache.translate(UserUtil.getCode()));
            goodsUnitConversionList.add(goodsUnitConversion);
        }
        // 拼接sql，批量执行新增操作
        importBatchSave(goodsUnitConversionList);

    }

    /**
     * 同步单个商品时，根据操作类型判断是插入还是更新
     *
     * @param request
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void singleGoodsUnitConversionSave(SingleitemSynchronizeRequest request, Map<String,String> unitMap){
        log.info("《《《《《 同步商品单位转换开始 5》》》》》");
        String shipmentPartyCode = request.getOwnerCode();
        //删除原有商品基本单位转换关系
        String goodsCode = request.getItem().getItemCode();
        this.remove(new QueryWrapper<GoodsUnitConversion>().lambda().eq(GoodsUnitConversion::getGoodsCode, goodsCode)
                .eq(GoodsUnitConversion::getFlag, NumConst.NUM_ONE).eq(GoodsUnitConversion::getDeleted,"0"));
        String unitName = request.getItem().getStockUnit();
        //根据货主code和单位名称查询单位信息
        GoodsUnitConversion goodsUnitConversion = new GoodsUnitConversion();
        goodsUnitConversion.setGoodsCode(goodsCode);
        goodsUnitConversion.setUnitCode(unitMap.get(shipmentPartyCode+"_"+unitName));
        goodsUnitConversion.setUnitName(request.getItem().getStockUnit());
        if (StrUtil.isNotEmpty(request.getItem().getLength())) {
            goodsUnitConversion.setLength(new BigDecimal(request.getItem().getLength()));
        }
        if (StrUtil.isNotEmpty(request.getItem().getWidth())) {
            goodsUnitConversion.setWeight(new BigDecimal(request.getItem().getWidth()));
        }
        if (StrUtil.isNotEmpty(request.getItem().getHeight())) {
            goodsUnitConversion.setWeight(new BigDecimal(request.getItem().getHeight()));
        }
        if (StrUtil.isNotEmpty(request.getItem().getVolume())) {
            goodsUnitConversion.setWeight(new BigDecimal(request.getItem().getVolume()));
        }
        if (StrUtil.isNotEmpty(request.getItem().getGrossWeight())) {
            goodsUnitConversion.setWeight(new BigDecimal(request.getItem().getGrossWeight()));
        }

        goodsUnitConversion.setGmtCreated(LocalDateTime.now());
        goodsUnitConversion.setCreatedBy(UserUtil.getCode());
        goodsUnitConversion.setCreatedName(partyCache.translate(UserUtil.getCode()));
        this.save(goodsUnitConversion);
        log.info("《《《《《 同步商品单位转换结束 5 》》》》》");
    }

    /**
     * 同步-批量保存操作
     * @param goodsUnitConversionList
     * @return
     */
    private int importBatchSave(List<GoodsUnitConversion> goodsUnitConversionList) {
        StringBuilder data = new StringBuilder();
        data.append("INSERT INTO `base_goods_unit_conversion`(`id`, `code`, `group_code`,`goods_code`,`unit_code`,`unit_name`, "
                + " `length`,`width`,`height`, `weight`,`volume`,`gmt_created`,`created_by`,`created_name`) values ");
        String sql = goodsUnitConversionList.stream().map(e -> makeInsertValueStr(e)).collect(Collectors.joining(","));
        data.append(sql);
        return this.baseMapper.execSql(data.toString());
    }

    /**
     * 同步-批量插入生成sql
     * @param goodsUnitConversion
     * @return
     */
    private StringBuilder makeInsertValueStr(final GoodsUnitConversion goodsUnitConversion) {
        StringBuilder data = new StringBuilder();
        data.append("(");
        // id
        data.append("default, ");
        // code
        data.append("'").append(IdUtil.simpleUUID()).append("', ");
        // group_code
        data.append("'").append(UserUtil.getBranchCode()).append("', ");
        // goods_code
        data.append("'").append(ObjectUtil.defaultIfNull(goodsUnitConversion.getGoodsCode(), StrUtil.EMPTY)).append("', ");
        // unit_code
        data.append("'").append(ObjectUtil.defaultIfNull(goodsUnitConversion.getUnitCode(), StrUtil.EMPTY)).append("', ");
        // unit_name
        data.append("'").append(ObjectUtil.defaultIfNull(goodsUnitConversion.getUnitName(), StrUtil.EMPTY)).append("', ");
        // length
        data.append("'").append(ObjectUtil.defaultIfNull(goodsUnitConversion.getLength(), BigDecimal.ZERO)).append("', ");
        // width
        data.append("'").append(ObjectUtil.defaultIfNull(goodsUnitConversion.getWidth(), BigDecimal.ZERO)).append("', ");
        // height
        data.append("'").append(ObjectUtil.defaultIfNull(goodsUnitConversion.getHeight(), BigDecimal.ZERO)).append("', ");
        // weight
        data.append("'").append(ObjectUtil.defaultIfNull(goodsUnitConversion.getWeight(), BigDecimal.ZERO)).append("', ");
        // volume
        data.append("'").append(ObjectUtil.defaultIfNull(goodsUnitConversion.getVolume(), BigDecimal.ZERO)).append("', ");
        // gmt_created
        data.append("'").append(ObjectUtil.defaultIfNull(goodsUnitConversion.getGmtCreated(), LocalDateTime.now())).append("', ");
        // created_by
        data.append("'").append(ObjectUtil.defaultIfNull(goodsUnitConversion.getCreatedBy(), StrUtil.EMPTY)).append("', ");
        // created_name
        data.append("'").append(ObjectUtil.defaultIfNull(goodsUnitConversion.getCreatedName(), StrUtil.EMPTY)).append("' ");
        data.append(")");
        return data;
    }

    /**
     * 根据 商品code、单位名称 获取 对象
     * @param goodCode
     * @param unitName
     * @return
     */
    @Override
    public GoodsUnitConversion goodsAndUnitName(String goodCode, String unitName) {
        return getOne(new QueryWrapper<GoodsUnitConversion>().lambda().eq(GoodsUnitConversion::getGoodsCode, goodCode).eq(GoodsUnitConversion::getUnitName, unitName));
    }

}
